package migrate

import (
	"context"
	"fmt"
	"reflect"
	"strconv"

	"device-admin/config"
	"device-admin/config/mysql"
	"device-admin/internal/define"
	"device-admin/internal/models"

	"192.168.1.75/go-pkg/logx"
)

// AutoMigrate 检查或更新数据库
func AutoMigrate() {
	db := mysql.NewDB()
	if config.Config.AutoMigrate {
		// 自动检查安装并升级
		hasDB := db.Migrator().HasTable("version")
		// 首次自动安装
		if !hasDB {
			if err := Install(); err != nil {
				fmt.Println(err.Error())
				panic(err.Error())
			}
		} else {
			// 数据库迁移
			Migrate()
		}
	}
}

// migrate 数据迁移
func Migrate() {
	var currentVer models.Version
	// 获取当前版本
	db := mysql.NewDB()
	db.Model(&models.Version{}).Take(&currentVer)
	// 旧版本
	oldDBVersion := currentVer.Version
	// 如果已是最新版本，则重复执行一次最近的迁移脚本（所以要保证迁移脚本的幂等）
	if oldDBVersion == define.DBVersion {
		CallScriptN(oldDBVersion)
	} else {
		for {
			oldDBVersion++
			// 如果中间版本不存在，则仅执行最新版本的迁移
			if success, err := CallScriptN(oldDBVersion); err != nil {
				logx.Error(context.Background(), "Migrate", logx.Err(err))
				break
			} else if success {
				// 执行成功后，保存当前版本记录到数据库
				db.Model(&models.Version{}).Where("id = ?", currentVer.ID).Updates(map[string]interface{}{
					"version": oldDBVersion,
				})
			}
			// 直到升级到最新版本
			if oldDBVersion >= define.DBVersion {
				break
			}
		}
	}
}

// CallScriptN 迁移脚本调用
func CallScriptN(verison int64) (success bool, err error) {
	// 获取对应版本的升级脚本,方法定义要大写，否则反射无法访问到
	funcName := "Script" + strconv.FormatInt(verison, 10)

	method := reflect.ValueOf(MigrateFunc{}).MethodByName(funcName)
	if method.IsValid() {
		// 第一次会重复执行最近一次的脚本，所以要保证迁移脚本的幂等性
		values := method.Call([]reflect.Value{})
		if err, ok := values[0].Interface().(error); ok {
			return false, err
		}
		return true, nil
	} else {
		return false, nil
	}
}
